{-|
Module: IHP.View.CSSFramework
Description: Adds support for bootstrap, tailwind, etc. to IHP
Copyright: (c) digitally induced GmbH, 2020
-}
module IHP.View.CSSFramework where

import IHP.Prelude
import Network.Wai.Middleware.FlashMessages (FlashMessage (..))
import qualified Text.Blaze.Html5 as Blaze
import IHP.HSX.QQ (hsx)
import IHP.HSX.ToHtml ()
import IHP.View.Types
import IHP.View.Classes

import IHP.ModelSupport
import IHP.Breadcrumb.Types
import IHP.Pagination.Helpers
import IHP.Pagination.Types


-- | Provides an unstyled CSSFramework
--
-- This way we can later add more properties to the CSSFramework without having to update all the CSS Frameworks manually
instance Default CSSFramework where
    def = CSSFramework
            {
                styledFlashMessage = \cssFramework -> \case
                        SuccessFlashMessage message -> [hsx|<div>{message}</div>|]
                        ErrorFlashMessage message -> [hsx|<div>{message}</div>|]
                , styledFlashMessages
                , styledFormField
                , styledTextFormField
                , styledTextareaFormField
                , styledCheckboxFormField
                , styledSelectFormField
                , styledRadioFormField
                , styledFormGroup
                , styledSubmitButton
                , styledSubmitButtonClass
                , styledFormFieldHelp
                , styledInputClass
                , styledInputInvalidClass
                , styledFormGroupClass
                , styledValidationResult
                , styledValidationResultClass
                , styledPagination
                , styledPaginationPageLink
                , styledPaginationDotDot
                , styledPaginationItemsPerPageSelector
                , styledPaginationLinkPrevious
                , styledPaginationLinkNext
                , styledBreadcrumb
                , styledBreadcrumbItem
            }
        where
            styledFlashMessages cssFramework flashMessages = forEach flashMessages (cssFramework.styledFlashMessage cssFramework)

            styledFormField :: CSSFramework -> FormField -> Blaze.Html
            styledFormField cssFramework@CSSFramework {styledValidationResult, styledTextFormField, styledCheckboxFormField, styledSelectFormField, styledRadioFormField, styledTextareaFormField} formField =
                formGroup renderInner
                where
                    renderInner = case formField.fieldType of
                        TextInput -> styledTextFormField cssFramework "text" formField validationResult
                        NumberInput -> styledTextFormField cssFramework "number" formField validationResult
                        UrlInput -> styledTextFormField cssFramework "url" formField validationResult
                        PasswordInput -> styledTextFormField cssFramework "password" formField validationResult
                        ColorInput -> styledTextFormField cssFramework "color" formField validationResult
                        EmailInput -> styledTextFormField cssFramework "email" formField validationResult
                        DateInput -> styledTextFormField cssFramework "date" formField validationResult
                        DateTimeInput -> styledTextFormField cssFramework "datetime-local" formField validationResult
                        CheckboxInput -> styledCheckboxFormField cssFramework formField validationResult
                        HiddenInput -> styledTextFormField cssFramework "hidden" formField validationResult
                        TextareaInput -> styledTextareaFormField cssFramework formField validationResult
                        SelectInput {} -> styledSelectFormField cssFramework formField validationResult
                        RadioInput {} -> styledRadioFormField cssFramework formField validationResult
                        FileInput -> styledTextFormField cssFramework "file" formField validationResult

                    validationResult :: Blaze.Html
                    validationResult = unless formField.disableValidationResult (styledValidationResult cssFramework formField)

                    -- | Wraps the input inside a @<div class="form-group">...</div>@ (unless @disableGroup = True@)
                    formGroup :: Blaze.Html -> Blaze.Html
                    formGroup renderInner = case formField of
                        FormField { disableGroup = True } -> renderInner
                        FormField { fieldInputId } -> styledFormGroup cssFramework fieldInputId renderInner


            styledFormGroup :: CSSFramework -> Text -> Blaze.Html -> Blaze.Html
            styledFormGroup cssFramework@CSSFramework {styledFormGroupClass} fieldInputId renderInner =
                [hsx|<div class={styledFormGroupClass} id={"form-group-" <> fieldInputId}>{renderInner}</div>|]

            styledCheckboxFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
            styledCheckboxFormField cssFramework@CSSFramework {styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, required, autofocus } validationResult = do
                [hsx|<div class="form-check">{element}</div>|]
                where
                    inputInvalidClass = styledInputInvalidClass cssFramework formField
                    helpText = styledFormFieldHelp cssFramework formField

                    -- If the checkbox is checked off, the browser will not send the parameter as part of the form.
                    -- This will then make it impossible to set a field to False using a checkbox.
                    -- For that we add the "hidden" input type.
                    theInput = [hsx|
                                    <input
                                        type="checkbox"
                                        name={fieldName}
                                        class={classes ["form-check-input", (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                                        id={fieldInputId}
                                        checked={fieldValue == "yes"}
                                        required={required}
                                        disabled={disabled}
                                        autofocus={autofocus}
                                        {...additionalAttributes}
                                    />

                                    <input type="hidden" name={fieldName} value={inputValue False} />
                            |]


                    element = if disableLabel
                        then [hsx|<div>
                                    {theInput}
                                    {validationResult}
                                    {helpText}
                                </div>
                            |]
                        else [hsx|
                                {theInput}
                                <label
                                    class={classes [("form-check-label", labelClass == ""), (labelClass, labelClass /= "")]}
                                    for={fieldInputId}
                                >
                                    {fieldLabel}
                                </label>

                                {validationResult}
                                {helpText}
                            |]

            styledTextFormField :: CSSFramework -> Text -> FormField -> Blaze.Html -> Blaze.Html
            styledTextFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} inputType formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, placeholder, required, autofocus } validationResult =
                [hsx|
                    {label}
                    <input
                        type={inputType}
                        name={fieldName}
                        placeholder={placeholder}
                        id={fieldInputId}
                        class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                        value={maybeValue}
                        required={required}
                        disabled={disabled}
                        autofocus={autofocus}
                        {...additionalAttributes}
                    />

                    {validationResult}
                    {helpText}
              |]
                where
                    label = unless (disableLabel || null fieldLabel) [hsx|<label class={classes ["form-label", (labelClass, labelClass /= "")]} for={fieldInputId}>{fieldLabel}</label>|]
                    inputClass = (styledInputClass cssFramework formField, True)
                    inputInvalidClass = styledInputInvalidClass cssFramework formField
                    helpText = styledFormFieldHelp cssFramework formField
                    -- If there's no value, then we want to hide the "value" attribute.
                    maybeValue = if fieldValue == "" then Nothing else Just fieldValue

            styledSelectFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
            styledSelectFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, placeholder, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, required, autofocus } validationResult =
                [hsx|
                    {label}
                    <select
                        name={fieldName}
                        id={fieldInputId}
                        class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                        value={fieldValue}
                        disabled={disabled}
                        required={required}
                        autofocus={autofocus}
                        {...additionalAttributes}
                    >
                        <option value="" selected={not isValueSelected} disabled={True}>{placeholder}</option>
                        {forEach (options fieldType) (getOption)}
                    </select>

                    {validationResult}
                    {helpText}
                |]
                where
                    label = unless disableLabel [hsx|<label class={classes ["form-label", (labelClass, labelClass /= "")]} for={fieldInputId}>{fieldLabel}</label>|]
                    inputClass = (styledInputClass cssFramework formField, True)
                    inputInvalidClass = styledInputInvalidClass cssFramework formField
                    helpText = styledFormFieldHelp cssFramework formField

                    isValueSelected = any (\(_, optionValue) -> optionValue == fieldValue) (options fieldType)

                    -- Get a single option.
                    getOption (optionLabel, optionValue) = [hsx|
                        <option value={optionValue} selected={optionValue == fieldValue}>
                            {optionLabel}
                        </option>
                    |]


            styledRadioFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
            styledRadioFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, placeholder, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, required, autofocus } validationResult =
                [hsx|
                    {label}
                    <fieldset>
                        {forEach (options fieldType) (getRadio)}
                    </fieldset>

                    {validationResult}
                    {helpText}
                |]
                where
                    label = unless disableLabel [hsx|<label class={classes ["form-label", (labelClass, labelClass /= "")]} for={fieldInputId}>{fieldLabel}</label>|]
                    inputInvalidClass = styledInputInvalidClass cssFramework formField
                    helpText = styledFormFieldHelp cssFramework formField

                    -- Get a single radio button.
                    getRadio (optionLabel, optionValue) = [hsx|
                        <div class="form-check">
                            <input
                                class={classes ["form-check-input", (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                                type="radio"
                                id={optionId}
                                name={fieldName}
                                value={optionValue}
                                checked={optionValue == fieldValue}
                                disabled={disabled}
                                required={required}
                                autofocus={autofocus}
                                {...additionalAttributes}
                            />
                            {label}
                        </div>
                    |]
                        where
                            optionId = fieldInputId <> "_" <> optionValue
                            label = unless disableLabel [hsx|<label class={classes ["form-check-label", (labelClass, labelClass /= "")]} for={optionId}>{optionLabel}</label>|]

            styledTextareaFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
            styledTextareaFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, placeholder, required, autofocus } validationResult =
                [hsx|
                    {label}
                    <textarea
                        name={fieldName}
                        placeholder={placeholder}
                        id={fieldInputId}
                        class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                        required={required}
                        disabled={disabled}
                        autofocus={autofocus}
                        {...additionalAttributes}
                    >{fieldValue}</textarea>{validationResult}{helpText}|]
                where
                    label = unless (disableLabel || null fieldLabel) [hsx|<label class={classes ["form-label", (labelClass, labelClass /= "")]} for={fieldInputId}>{fieldLabel}</label>|]
                    inputClass = (styledInputClass cssFramework formField, True)
                    inputInvalidClass = styledInputInvalidClass cssFramework formField
                    helpText = styledFormFieldHelp cssFramework formField

            styledValidationResult :: CSSFramework -> FormField -> Blaze.Html
            styledValidationResult cssFramework formField@FormField { validatorResult = Just violation } =
                let
                    className :: Text = cssFramework.styledValidationResultClass
                    message = case violation of
                        TextViolation text -> [hsx|{text}|]
                        HtmlViolation html -> Blaze.preEscapedToHtml html
                in
                    [hsx|<div class={className}>{message}</div>|]
            styledValidationResult _ _ = mempty

            styledValidationResultClass = ""

            styledSubmitButton cssFramework SubmitButton { label, buttonClass, buttonDisabled } =
                let className :: Text = cssFramework.styledSubmitButtonClass
                in [hsx|<button class={classes [(className, True), (buttonClass, not (null buttonClass))]} disabled={buttonDisabled} type="submit">{label}</button>|]

            styledInputClass _ _ = ""
            styledInputInvalidClass _ _ = "invalid"

            styledFormGroupClass = ""

            styledFormFieldHelp _ FormField { helpText = "" } = mempty
            styledFormFieldHelp _ FormField { helpText } = [hsx|<p>{helpText}</p>|]

            styledSubmitButtonClass = ""

            styledPagination :: CSSFramework -> PaginationView -> Blaze.Html
            styledPagination _ paginationView =
                [hsx|

                <div class="d-flex justify-content-md-center">
                    <nav aria-label="Page Navigator" class="mr-2">
                        <ul class="pagination">
                            {paginationView.linkPrevious}
                            {paginationView.pageDotDotItems}
                            {paginationView.linkNext}
                        </ul>
                    </nav>

                    <div class="form-row">
                        <div class="col-auto mr-2">
                            <select class="custom-select" id="maxItemsSelect" onchange="window.location.href = this.options[this.selectedIndex].dataset.url">
                                {paginationView.itemsPerPageSelector}
                            </select>
                        </div>
                    </div>

                </div>
                |]

            styledPaginationPageLink :: CSSFramework -> Pagination -> ByteString -> Int -> Blaze.Html
            styledPaginationPageLink _ pagination@Pagination {currentPage} pageUrl pageNumber =
                let
                    linkClass = classes ["page-item", ("active", pageNumber == currentPage)]
                in
                    [hsx|<li class={linkClass}><a class="page-link" href={pageUrl}>{show pageNumber}</a></li>|]


            styledPaginationDotDot :: CSSFramework -> Pagination -> Blaze.Html
            styledPaginationDotDot _ _ =
                [hsx|<li class="page-item"><a class="page-link">…</a></li>|]

            styledPaginationItemsPerPageSelector :: CSSFramework -> Pagination -> (Int -> ByteString) -> Blaze.Html
            styledPaginationItemsPerPageSelector _ pagination@Pagination {pageSize} itemsPerPageUrl =
                let
                    oneOption :: Int -> Blaze.Html
                    oneOption n = [hsx|<option value={show n} selected={n == pageSize} data-url={itemsPerPageUrl n}>{n} items per page</option>|]
                in
                    [hsx|{forEach [10,20,50,100,200] oneOption}|]

            styledPaginationLinkPrevious :: CSSFramework -> Pagination -> ByteString -> Blaze.Html
            styledPaginationLinkPrevious _ pagination@Pagination {currentPage} pageUrl =
                let
                    prevClass = classes ["page-item", ("disabled", not $ hasPreviousPage pagination)]
                    url = if hasPreviousPage pagination then pageUrl else "#"
                in
                    [hsx|
                        <li class={prevClass}>
                            <a class="page-link" href={url} aria-label="Previous">
                                <span aria-hidden="true">&laquo;</span>
                                <span class="sr-only">Previous</span>
                            </a>
                        </li>
                    |]

            styledPaginationLinkNext :: CSSFramework -> Pagination -> ByteString -> Blaze.Html
            styledPaginationLinkNext _ pagination@Pagination {currentPage} pageUrl =
                let
                    nextClass = classes ["page-item", ("disabled", not $ hasNextPage pagination)]
                    url = if hasNextPage pagination then pageUrl else "#"
                in
                    [hsx|
                        <li class={nextClass}>
                            <a class="page-link" href={url} aria-label="Next">
                                <span aria-hidden="true">&raquo;</span>
                                <span class="sr-only">Next</span>
                            </a>
                        </li>
                    |]

            styledBreadcrumb :: CSSFramework -> [BreadcrumbItem]-> BreadcrumbsView -> Blaze.Html
            styledBreadcrumb _ _ breadcrumbsView = [hsx|
                <nav>
                    <ol class="breadcrumb">
                        {breadcrumbsView.breadcrumbItems}

                    </ol>
                </nav>
            |]


            styledBreadcrumbItem :: CSSFramework -> [ BreadcrumbItem ]-> BreadcrumbItem -> Bool -> Blaze.Html
            styledBreadcrumbItem _ breadcrumbItems breadcrumbItem@BreadcrumbItem {breadcrumbLabel, url} isLast =
                let
                    breadcrumbsClasses = classes ["breadcrumb-item", ("active", isLast)]
                in
                case url of
                    Nothing ->  [hsx|<li class={breadcrumbsClasses}>{breadcrumbLabel}</li>|]
                    Just url -> [hsx|<li class={breadcrumbsClasses}><a href={url}>{breadcrumbLabel}</a></li>|]



bootstrap :: CSSFramework
bootstrap = def
    { styledFlashMessage
    , styledSubmitButtonClass
    , styledFormGroupClass
    , styledFormFieldHelp
    , styledInputClass
    , styledInputInvalidClass
    , styledValidationResultClass
    }
    where
        styledFlashMessage _ (SuccessFlashMessage message) = [hsx|<div class="alert alert-success">{message}</div>|]
        styledFlashMessage _ (ErrorFlashMessage message) = [hsx|<div class="alert alert-danger">{message}</div>|]

        styledInputClass _ FormField { fieldType = FileInput } = "form-control-file"
        styledInputClass _ FormField {} = "form-control"
        styledInputInvalidClass _ _ = "is-invalid"

        styledFormFieldHelp _ FormField { helpText = "" } = mempty
        styledFormFieldHelp _ FormField { helpText } = [hsx|<small class="form-text">{helpText}</small>|]

        styledFormGroupClass = "mb-3"

        styledValidationResultClass = "invalid-feedback"

        styledSubmitButtonClass = "btn btn-primary"

bootstrap4 :: CSSFramework
bootstrap4 = def
    { styledFlashMessage
    , styledFormField
    , styledTextFormField
    , styledTextareaFormField
    , styledCheckboxFormField
    , styledSelectFormField
    , styledFormGroup
    , styledSubmitButton
    , styledSubmitButtonClass
    , styledFormFieldHelp
    , styledInputClass
    , styledInputInvalidClass
    , styledFormGroupClass
    , styledValidationResult
    , styledValidationResultClass
    , styledPagination
    , styledPaginationPageLink
    , styledPaginationDotDot
    , styledPaginationItemsPerPageSelector
    , styledPaginationLinkPrevious
    , styledPaginationLinkNext
    , styledBreadcrumb
    , styledBreadcrumbItem
    }
    where
        styledFlashMessage _ (SuccessFlashMessage message) = [hsx|<div class="alert alert-success">{message}</div>|]
        styledFlashMessage _ (ErrorFlashMessage message) = [hsx|<div class="alert alert-danger">{message}</div>|]

        styledInputClass _ FormField { fieldType = FileInput } = "form-control-file"
        styledInputClass _ FormField {} = "form-control"
        styledInputInvalidClass _ _ = "is-invalid"

        styledFormFieldHelp _ FormField { helpText = "" } = mempty
        styledFormFieldHelp _ FormField { helpText } = [hsx|<small class="form-text text-muted">{helpText}</small>|]

        styledFormGroupClass = "form-group"

        styledValidationResultClass = "invalid-feedback"

        styledSubmitButtonClass = "btn btn-primary"


        styledFormField :: CSSFramework -> FormField -> Blaze.Html
        styledFormField cssFramework@CSSFramework {styledValidationResult, styledTextFormField, styledCheckboxFormField, styledSelectFormField, styledRadioFormField, styledTextareaFormField} formField =
            formGroup renderInner
            where
                renderInner = case formField.fieldType of
                    TextInput -> styledTextFormField cssFramework "text" formField validationResult
                    NumberInput -> styledTextFormField cssFramework "number" formField validationResult
                    PasswordInput -> styledTextFormField cssFramework "password" formField validationResult
                    ColorInput -> styledTextFormField cssFramework "color" formField validationResult
                    EmailInput -> styledTextFormField cssFramework "email" formField validationResult
                    DateInput -> styledTextFormField cssFramework "date" formField validationResult
                    DateTimeInput -> styledTextFormField cssFramework "datetime-local" formField validationResult
                    CheckboxInput -> styledCheckboxFormField cssFramework formField validationResult
                    HiddenInput -> styledTextFormField cssFramework "hidden" formField { disableLabel = True, disableGroup = True, disableValidationResult = True } validationResult
                    TextareaInput -> styledTextareaFormField cssFramework formField validationResult
                    SelectInput {} -> styledSelectFormField cssFramework formField validationResult
                    RadioInput {} -> styledRadioFormField cssFramework formField validationResult
                    FileInput -> styledTextFormField cssFramework "file" formField validationResult

                validationResult :: Blaze.Html
                validationResult = unless formField.disableValidationResult (styledValidationResult cssFramework formField)

                -- | Wraps the input inside a @<div class="form-group">...</div>@ (unless @disableGroup = True@)
                formGroup :: Blaze.Html -> Blaze.Html
                formGroup renderInner = case formField of
                    FormField { disableGroup = True } -> renderInner
                    FormField { fieldInputId } -> styledFormGroup cssFramework fieldInputId renderInner


        styledFormGroup :: CSSFramework -> Text -> Blaze.Html -> Blaze.Html
        styledFormGroup cssFramework@CSSFramework {styledFormGroupClass} fieldInputId renderInner =
            [hsx|<div class={styledFormGroupClass} id={"form-group-" <> fieldInputId}>{renderInner}</div>|]

        styledCheckboxFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledCheckboxFormField cssFramework@CSSFramework {styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, required, autofocus } validationResult = do
            [hsx|<div class="form-check">{element}</div>|]
            where
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField

                -- If the checkbox is checked off, the browser will not send the parameter as part of the form.
                -- This will then make it impossible to set a field to False using a checkbox.
                -- For that we add the "hidden" input type.
                theInput = [hsx|
                                <input
                                    type="checkbox"
                                    name={fieldName}
                                    class={classes ["form-check-input", (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                                    id={fieldInputId}
                                    checked={fieldValue == "yes"}
                                    required={required}
                                    disabled={disabled}
                                    autofocus={autofocus}
                                    {...additionalAttributes}
                                />

                                <input type="hidden" name={fieldName} value={inputValue False} />
                        |]


                element = if disableLabel
                    then [hsx|<div>
                                {theInput}
                                {validationResult}
                                {helpText}
                            </div>
                        |]
                    else [hsx|
                            {theInput}
                            <label
                                class={classes [("form-check-label", labelClass == ""), (labelClass, labelClass /= "")]}
                                for={fieldInputId}
                            >
                                {fieldLabel}
                            </label>

                            {validationResult}
                            {helpText}
                        |]

        styledTextFormField :: CSSFramework -> Text -> FormField -> Blaze.Html -> Blaze.Html
        styledTextFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} inputType formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, placeholder, required, autofocus } validationResult =
            [hsx|
                {label}
                <input
                    type={inputType}
                    name={fieldName}
                    placeholder={placeholder}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    value={maybeValue}
                    required={required}
                    disabled={disabled}
                    autofocus={autofocus}
                    {...additionalAttributes}
                />

                {validationResult}
                {helpText}
          |]
            where
                label = unless (disableLabel || null fieldLabel) [hsx|<label class={labelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass = (styledInputClass cssFramework formField, True)
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField
                -- If there's no value, then we want to hide the "value" attribute.
                maybeValue = if fieldValue == "" then Nothing else Just fieldValue

        styledSelectFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledSelectFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, placeholder, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, required, autofocus } validationResult =
            [hsx|
                {label}
                <select
                    name={fieldName}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    value={fieldValue}
                    disabled={disabled}
                    required={required}
                    autofocus={autofocus}
                    {...additionalAttributes}
                >
                    <option selected={not isValueSelected} disabled={True}>{placeholder}</option>
                    {forEach (options fieldType) (getOption)}
                </select>

                {validationResult}
                {helpText}
            |]
            where
                label = unless disableLabel [hsx|<label class={labelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass = (styledInputClass cssFramework formField, True)
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField

                isValueSelected = any (\(_, optionValue) -> optionValue == fieldValue) (options fieldType)

                -- Get a single option.
                getOption (optionLabel, optionValue) = [hsx|
                    <option value={optionValue} selected={optionValue == fieldValue}>
                        {optionLabel}
                    </option>
                |]

        styledTextareaFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledTextareaFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, placeholder, required, autofocus } validationResult =
            [hsx|
                {label}
                <textarea
                    name={fieldName}
                    placeholder={placeholder}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    required={required}
                    disabled={disabled}
                    autofocus={autofocus}
                    {...additionalAttributes}
                >{fieldValue}</textarea>{validationResult}{helpText}|]
            where
                label = unless (disableLabel || null fieldLabel) [hsx|<label class={labelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass = (styledInputClass cssFramework formField, True)
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField

        styledValidationResult :: CSSFramework -> FormField -> Blaze.Html
        styledValidationResult cssFramework formField@FormField { validatorResult = Just violation } =
            let
                className :: Text = cssFramework.styledValidationResultClass
                message = case violation of
                    TextViolation text -> [hsx|{text}|]
                    HtmlViolation html -> Blaze.preEscapedToHtml html
            in
                [hsx|<div class={className}>{message}</div>|]
        styledValidationResult _ _ = mempty

        styledSubmitButton cssFramework SubmitButton { label, buttonClass, buttonDisabled } =
            let className :: Text = cssFramework.styledSubmitButtonClass
            in [hsx|<button class={classes [(className, True), (buttonClass, not (null buttonClass))]} disabled={buttonDisabled} type="submit">{label}</button>|]

        styledPagination :: CSSFramework -> PaginationView -> Blaze.Html
        styledPagination _ paginationView =
            [hsx|

            <div class="d-flex justify-content-md-center">
                <nav aria-label="Page Navigator" class="mr-2">
                    <ul class="pagination">
                        {paginationView.linkPrevious}
                        {paginationView.pageDotDotItems}
                        {paginationView.linkNext}
                    </ul>
                </nav>

                <div class="form-row">
                    <div class="col-auto mr-2">
                        <select class="custom-select" id="maxItemsSelect" onchange="window.location.href = this.options[this.selectedIndex].dataset.url">
                            {paginationView.itemsPerPageSelector}
                        </select>
                    </div>
                </div>

            </div>
            |]

        styledPaginationPageLink :: CSSFramework -> Pagination -> ByteString -> Int -> Blaze.Html
        styledPaginationPageLink _ pagination@Pagination {currentPage} pageUrl pageNumber =
            let
                linkClass = classes ["page-item", ("active", pageNumber == currentPage)]
            in
                [hsx|<li class={linkClass}><a class="page-link" href={pageUrl}>{show pageNumber}</a></li>|]


        styledPaginationDotDot :: CSSFramework -> Pagination -> Blaze.Html
        styledPaginationDotDot _ _ =
            [hsx|<li class="page-item"><a class="page-link">…</a></li>|]

        styledPaginationItemsPerPageSelector :: CSSFramework -> Pagination -> (Int -> ByteString) -> Blaze.Html
        styledPaginationItemsPerPageSelector _ pagination@Pagination {pageSize} itemsPerPageUrl =
            let
                oneOption :: Int -> Blaze.Html
                oneOption n = [hsx|<option value={show n} selected={n == pageSize} data-url={itemsPerPageUrl n}>{n} items per page</option>|]
            in
                [hsx|{forEach [10,20,50,100,200] oneOption}|]

        styledPaginationLinkPrevious :: CSSFramework -> Pagination -> ByteString -> Blaze.Html
        styledPaginationLinkPrevious _ pagination@Pagination {currentPage} pageUrl =
            let
                prevClass = classes ["page-item", ("disabled", not $ hasPreviousPage pagination)]
                url = if hasPreviousPage pagination then pageUrl else "#"
            in
                [hsx|
                    <li class={prevClass}>
                        <a class="page-link" href={url} aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                            <span class="sr-only">Previous</span>
                        </a>
                    </li>
                |]

        styledPaginationLinkNext :: CSSFramework -> Pagination -> ByteString -> Blaze.Html
        styledPaginationLinkNext _ pagination@Pagination {currentPage} pageUrl =
            let
                nextClass = classes ["page-item", ("disabled", not $ hasNextPage pagination)]
                url = if hasNextPage pagination then pageUrl else "#"
            in
                [hsx|
                    <li class={nextClass}>
                        <a class="page-link" href={url} aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                            <span class="sr-only">Next</span>
                        </a>
                    </li>
                |]

        styledBreadcrumb :: CSSFramework -> [BreadcrumbItem]-> BreadcrumbsView -> Blaze.Html
        styledBreadcrumb _ _ breadcrumbsView = [hsx|
            <nav>
                <ol class="breadcrumb">
                    {breadcrumbsView.breadcrumbItems}

                </ol>
            </nav>
        |]


        styledBreadcrumbItem :: CSSFramework -> [ BreadcrumbItem ]-> BreadcrumbItem -> Bool -> Blaze.Html
        styledBreadcrumbItem _ breadcrumbItems breadcrumbItem@BreadcrumbItem {breadcrumbLabel, url} isLast =
            let
                breadcrumbsClasses = classes ["breadcrumb-item", ("active", isLast)]
            in
            case url of
                Nothing ->  [hsx|<li class={breadcrumbsClasses}>{breadcrumbLabel}</li>|]
                Just url -> [hsx|<li class={breadcrumbsClasses}><a href={url}>{breadcrumbLabel}</a></li>|]




tailwind :: CSSFramework
tailwind = def
    { styledFlashMessage
    , styledTextFormField
    , styledTextareaFormField
    , styledCheckboxFormField
    , styledSelectFormField
    , styledRadioFormField
    , styledSubmitButtonClass
    , styledFormGroupClass
    , styledFormFieldHelp
    , styledInputClass
    , styledInputInvalidClass
    , styledValidationResultClass
    , styledPagination
    , styledPaginationLinkPrevious
    , styledPaginationLinkNext
    , styledPaginationPageLink
    , styledPaginationDotDot
    , styledPaginationItemsPerPageSelector
    , styledBreadcrumb
    , styledBreadcrumbItem
    }
    where
        styledFlashMessage _ (SuccessFlashMessage message) = [hsx|<div class="bg-green-100 border border-green-500 text-green-900 px-4 py-3 rounded relative">{message}</div>|]
        styledFlashMessage _ (ErrorFlashMessage message) = [hsx|<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative">{message}</div>|]

        styledCheckboxFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledCheckboxFormField cssFramework@CSSFramework {styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, required, autofocus } validationResult = do
            [hsx|<div class="form-check">{element}</div>|]
            where
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField

                theInput = [hsx|
                            <div>
                                <input
                                    type="checkbox"
                                    name={fieldName}
                                    class={classes ["form-check-input", (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                                    id={fieldInputId}
                                    checked={fieldValue == "yes"}
                                    required={required}
                                    disabled={disabled}
                                    autofocus={autofocus}
                                    {...additionalAttributes}
                                />

                                <input type="hidden" name={fieldName} value={inputValue False} />
                            </div>
                        |]


                element = if disableLabel
                    then [hsx|<div class="flex flex-row space-x-2">
                                {theInput}
                                <div class="flex flex-col space-y-2">
                                    {validationResult}
                                    {helpText}
                                </div>
                            </div>
                        |]
                    else [hsx|
                            <div class="flex flex-row space-x-2">
                                {theInput}
                                <div class="flex flex-col">
                                    <label
                                        class={classes ["font-medium text-gray-700", ("form-check-label", labelClass == ""), (labelClass, labelClass /= "")]}
                                        for={fieldInputId}
                                    >
                                        {fieldLabel}
                                    </label>

                                    {validationResult}
                                    {helpText}
                                </div>
                            </div>
                        |]

        styledTextFormField :: CSSFramework -> Text -> FormField -> Blaze.Html -> Blaze.Html
        styledTextFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} inputType formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, placeholder, required, autofocus } validationResult =
            [hsx|
                {label}
                <input
                    type={inputType}
                    name={fieldName}
                    placeholder={placeholder}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    value={maybeValue}
                    required={required}
                    disabled={disabled}
                    autofocus={autofocus}
                    {...additionalAttributes}
                />

                {validationResult}
                {helpText}
            |]
            where
                twLabelClass = "font-medium text-gray-700" <> " " <> labelClass
                label = unless (disableLabel || null fieldLabel) [hsx|<label class={twLabelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass = (styledInputClass cssFramework formField, True)
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField
                -- If there's no value, then we want to hide the "value" attribute.
                maybeValue = if fieldValue == "" then Nothing else Just fieldValue


        styledTextareaFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledTextareaFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, placeholder, required, autofocus } validationResult =
            [hsx|
                {label}
                <textarea
                    name={fieldName}
                    placeholder={placeholder}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    required={required}
                    disabled={disabled}
                    autofocus={autofocus}
                    {...additionalAttributes}
                >{fieldValue}</textarea>{validationResult}{helpText}
            |]
            where
                twLabelClass = classes ["font-medium text-gray-700", (labelClass, not (null labelClass))]
                label = unless (disableLabel || null fieldLabel) [hsx|<label class={twLabelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass = (styledInputClass cssFramework formField, True)
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField


        styledSelectFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledSelectFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, placeholder, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, required, autofocus } validationResult =
            [hsx|
                {label}
                <select
                    name={fieldName}
                    id={fieldInputId}
                    class={classes [inputClass, (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    value={fieldValue}
                    disabled={disabled}
                    required={required}
                    autofocus={autofocus}
                    {...additionalAttributes}
                >
                    <option selected={not isValueSelected} disabled={True}>{placeholder}</option>
                    {forEach (options fieldType) (getOption)}
                </select>

                {validationResult}
                {helpText}
            |]
            where
                twLabelClass = "font-medium text-gray-700" <> " " <> labelClass
                label = unless disableLabel [hsx|<label class={twLabelClass} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass = (styledInputClass cssFramework formField, True)
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField

                isValueSelected = any (\(_, optionValue) -> optionValue == fieldValue) (options fieldType)

                -- Get a single option.
                getOption (optionLabel, optionValue) = [hsx|
                    <option value={optionValue} selected={optionValue == fieldValue}>
                        {optionLabel}
                    </option>
                |]

        styledRadioFormField :: CSSFramework -> FormField -> Blaze.Html -> Blaze.Html
        styledRadioFormField cssFramework@CSSFramework {styledInputClass, styledInputInvalidClass, styledFormFieldHelp} formField@FormField {fieldType, fieldName, placeholder, fieldLabel, fieldValue, fieldInputId, validatorResult, fieldClass, disabled, disableLabel, disableValidationResult, additionalAttributes, labelClass, required, autofocus } validationResult =
            [hsx|
                {label}
                <fieldset
                    class={classes ["flex flex-col gap-2", (inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                    autofocus={autofocus}
                    {...additionalAttributes}
                >

                    {forEach (options fieldType) (getRadio)}
                </fieldset>

                {validationResult}
                {helpText}
            |]
            where
                label = unless disableLabel [hsx|<label class={classes ["form-label", (labelClass, labelClass /= "")]} for={fieldInputId}>{fieldLabel}</label>|]
                inputClass = (styledInputClass cssFramework formField, True)
                inputInvalidClass = styledInputInvalidClass cssFramework formField
                helpText = styledFormFieldHelp cssFramework formField

                -- Get a single radio button.
                getRadio (optionLabel, optionValue) = [hsx|
                    <div class="flex flex-row gap-2 items-center">
                        <input
                            class={classes [(inputInvalidClass, isJust validatorResult), (fieldClass, not (null fieldClass))]}
                            type="radio"
                            id={optionId}
                            name={fieldName}
                            value={optionValue}
                            checked={optionValue == fieldValue}
                            disabled={disabled}
                            required={required}
                            autofocus={autofocus}
                            {...additionalAttributes}
                        />
                        {label}
                    </div>
                |]
                    where
                        optionId = fieldInputId <> "_" <> optionValue
                        label = unless disableLabel [hsx|<label class={classes ["form-label", (labelClass, labelClass /= "")]} for={optionId}>{optionLabel}</label>|]


        styledInputClass _ FormField {} = "focus:ring-blue-500 focus:border-blue-500 block w-full border-gray-300 rounded-md"
        styledInputInvalidClass _ _ = "is-invalid"

        styledSubmitButtonClass = "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"

        styledFormFieldHelp _ FormField { helpText = "" } = mempty
        styledFormFieldHelp _ FormField { helpText } = [hsx|<p class="text-gray-600 text-xs italic">{helpText}</p>|]

        styledFormGroupClass = "flex flex-col my-6 space-y-2"

        styledValidationResultClass = "text-red-500 text-xs italic"

        styledPagination :: CSSFramework -> PaginationView -> Blaze.Html
        styledPagination _ paginationView@PaginationView {pageUrl, pagination} =
            let
                currentPage = pagination.currentPage

                previousPageUrl = if hasPreviousPage pagination then pageUrl $ currentPage - 1 else "#"
                nextPageUrl = if hasNextPage pagination then pageUrl $ currentPage + 1 else "#"

                defaultClass = "relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
                previousClass = classes
                    [ defaultClass
                    , ("disabled", not $ hasPreviousPage pagination)
                    ]
                nextClass = classes
                    [ defaultClass
                    , ("disabled", not $ hasNextPage pagination)
                    ]

                previousMobileOnly =
                    [hsx|
                        <a href={previousPageUrl} class={previousClass}>
                            Previous
                        </a>
                    |]

                nextMobileOnly =
                    [hsx|
                        <a href={nextPageUrl} class={nextClass}>
                            Next
                        </a>
                    |]

            in
            [hsx|
                <div class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
                    <div class="flex-1 flex justify-between sm:hidden">
                        {previousMobileOnly}
                        {nextMobileOnly}
                    </div>
                    <div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
                        <div class="text-sm text-gray-700">
                            <select class="px-4 py-3" id="maxItemsSelect" onchange="window.location.href = this.options[this.selectedIndex].dataset.url">
                                {paginationView.itemsPerPageSelector}
                            </select>
                        </div>
                        <div>
                        <nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
                            {paginationView.linkPrevious}

                            {paginationView.pageDotDotItems}

                            {paginationView.linkNext}
                        </nav>
                        </div>
                    </div>
                </div>
            |]

        styledPaginationLinkPrevious :: CSSFramework -> Pagination -> ByteString -> Blaze.Html
        styledPaginationLinkPrevious _ pagination@Pagination {currentPage} pageUrl =
            let
                prevClass = classes
                    [ "relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
                    , ("disabled", not $ hasPreviousPage pagination)
                    ]

                url = if hasPreviousPage pagination then pageUrl else "#"

            in
                [hsx|
                    <a href={url} class={prevClass}>
                        <span class="sr-only">Previous</span>
                        <!-- Heroicon name: solid/chevron-left -->
                        <svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
                            <path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
                        </svg>
                    </a>
                |]

        styledPaginationLinkNext :: CSSFramework -> Pagination -> ByteString -> Blaze.Html
        styledPaginationLinkNext _ pagination@Pagination {currentPage} pageUrl =
            let
                nextClass = classes
                    [ "relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
                    , ("disabled", not $ hasNextPage pagination)
                    ]

                url = if hasNextPage pagination then pageUrl else "#"
            in
                [hsx|
                    <a href={url} class={nextClass}>
                        <span class="sr-only">Next</span>
                        <!-- Heroicon name: solid/chevron-right -->
                        <svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
                            <path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
                        </svg>
                    </a>

                |]

        styledPaginationPageLink :: CSSFramework -> Pagination -> ByteString -> Int -> Blaze.Html
        styledPaginationPageLink _ pagination@Pagination {currentPage} pageUrl pageNumber =
            let
                linkClass = classes
                    [ "relative inline-flex items-center px-4 py-2 border text-sm font-medium"
                    -- Current page
                    , ("z-10 bg-blue-50 border-blue-500 text-blue-600", pageNumber == currentPage)
                    -- Not current page
                    , ("bg-white border-gray-300 text-gray-500 hover:bg-gray-50", pageNumber /= currentPage)
                    ]
            in
                [hsx|
                    <a href={pageUrl} aria-current={pageNumber == currentPage} class={linkClass}>
                        {show pageNumber}
                    </a>
                |]


        styledPaginationDotDot :: CSSFramework -> Pagination -> Blaze.Html
        styledPaginationDotDot _ _ =
            [hsx|
                <span class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700">
                    ...
                </span>
        |]


        styledPaginationItemsPerPageSelector :: CSSFramework -> Pagination -> (Int -> ByteString) -> Blaze.Html
        styledPaginationItemsPerPageSelector _ pagination@Pagination {pageSize} itemsPerPageUrl =
            let
                oneOption :: Int -> Blaze.Html
                oneOption n = [hsx|<option value={show n} selected={n == pageSize} data-url={itemsPerPageUrl n}>{n} items per page</option>|]
            in
                [hsx|{forEach [10,20,50,100,200] oneOption}|]


        styledBreadcrumb :: CSSFramework -> [BreadcrumbItem]-> BreadcrumbsView -> Blaze.Html
        styledBreadcrumb _ _ breadcrumbsView = [hsx|
            <nav class="breadcrumbs bg-white my-4" aria-label="Breadcrumb">
                <ol class="flex items-center space-x-2" role="list">
                    {breadcrumbsView.breadcrumbItems}
                </ol>
            </nav>
        |]


        styledBreadcrumbItem :: CSSFramework -> [ BreadcrumbItem ]-> BreadcrumbItem -> Bool -> Blaze.Html
        styledBreadcrumbItem _ breadcrumbItems breadcrumbItem@BreadcrumbItem {breadcrumbLabel, url} isLast =
            let
                breadcrumbsClasses = classes ["flex flex-row space-x-2 text-gray-600 items-center", ("active", isLast)]

                -- Show chevron if item isn't the active one (i.e. the last one).
                chevronRight = unless isLast [hsx|
                <!-- heroicons.com chevron-right -->
                <svg xmlns="http://www.w3.org/2000/svg" class="flex-shrink-0 h-4 w-4 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
                </svg>
                |]
            in
            case url of
                Nothing ->  [hsx|
                    <li class={breadcrumbsClasses}>
                        {breadcrumbLabel}
                        {chevronRight}
                    </li>
                |]
                Just url -> [hsx|
                    <li class={breadcrumbsClasses}>
                        <a class="hover:text-gray-700" href={url}>{breadcrumbLabel}</a>
                        {chevronRight}
                    </li>
                    |]
